Skip to content

feat(sync): handle duplicate skill names across plugins#27

Merged
christso merged 9 commits intomainfrom
feat/duplicate-skill-naming
Jan 28, 2026
Merged

feat(sync): handle duplicate skill names across plugins#27
christso merged 9 commits intomainfrom
feat/duplicate-skill-naming

Conversation

@christso
Copy link
Copy Markdown
Contributor

Summary

  • Add deterministic naming resolution for duplicate skill folder names across plugins
  • When skill folder names conflict across different plugins, qualify with plugin name: {plugin}_{skill}
  • When both skill folder AND plugin names conflict, add org/hash prefix: {org}_{plugin}_{skill} (GitHub) or {hash}_{plugin}_{skill} (local)
  • Backward compatible: no conflicts = original folder names preserved

Changes

  • src/utils/hash.ts - 6-char deterministic hash utility for local path disambiguation
  • src/utils/source-parser.ts - Extract org from GitHub source URLs
  • src/utils/skill-name-resolver.ts - Three-tier naming resolution logic
  • src/core/transform.ts - Two-pass skill copying with name resolution
  • src/core/sync.ts - Collect all skills before copying, resolve names globally

Test Plan

  • Unit tests for hash utility (10 tests)
  • Unit tests for source parser (38 tests)
  • Unit tests for skill name resolver (29 tests)
  • Unit tests for skill resolution in sync (8 tests)
  • Integration tests for local source scenarios (17 tests)
  • Integration tests for GitHub source scenarios (8 tests)
  • All 262 tests pass

🤖 Generated with Claude Code

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Jan 28, 2026

Deploying allagents with  Cloudflare Pages  Cloudflare Pages

Latest commit: a932c0c
Status: ✅  Deploy successful!
Preview URL: https://6f5a4adc.allagents.pages.dev
Branch Preview URL: https://feat-duplicate-skill-naming.allagents.pages.dev

View logs

@christso christso force-pushed the feat/duplicate-skill-naming branch from 1f508d1 to 472b42b Compare January 28, 2026 01:25
christso and others added 8 commits January 28, 2026 12:29
Add getShortId() function that generates a deterministic 6-character
hexadecimal hash from a string input using SHA-256. This will be used
for local path disambiguation when multiple plugins have skills with
the same folder name and plugin name.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add extractOrgFromSource() function that extracts the organization/owner
from various GitHub source URL formats. This is used for skill name
disambiguation when multiple plugins have skills with the same folder
name and plugin name.

Supports:
- github:org/repo and github:org/repo#branch
- gh:org/repo and gh:org/repo#branch
- https://github.com/org/repo and full URLs with paths
- github.com/org/repo (no protocol)
- org/repo shorthand format
- Returns null for local paths (caller uses hash fallback)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements three-tier naming resolution for skills with duplicate names:
1. No conflict - use skill folder name as-is
2. Folder name conflicts - qualify with plugin name: {plugin}_{skill}
3. Both conflict - add org/hash prefix: {orgOrUuid}_{plugin}_{skill}

Uses getShortId() for local paths and extractOrgFromSource() for GitHub.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactors the sync process to collect all skills from all plugins before
copying, enabling automatic duplicate skill name handling:

- Add SkillCopyOptions and PluginCopyOptions interfaces to transform.ts
- Add collectPluginSkills() to gather skill entries from plugins
- Add getPluginName() to read plugin name from plugin.json or fallback
  to directory name
- Modify copySkills() to accept optional skillNameMap for resolved names
- Add collectAllSkills() and buildPluginSkillNameMaps() to sync.ts
- Update syncWorkspace() to use two-pass resolution:
  Pass 1: Collect all skills from validated plugins
  Pass 2: Copy skills using resolved names from the skill name resolver

When skill folder names conflict:
- Unique plugins qualify with plugin name: {plugin}_{skill}
- Same plugin names add org/hash prefix: {org}_{plugin}_{skill}

Backward compatible: when no conflicts, skills use original folder names.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive integration tests that verify the full sync flow
with duplicate skills across multiple scenarios:

- No conflict: skill names unchanged
- Skill conflict with different plugins: {plugin}_{skill} format
- Skill + plugin conflict with local sources: {hash}_{plugin}_{skill} format
- Mixed conflict levels in single workspace
- State tracking and purging of renamed skills
- Skill content preservation during renaming
- Edge cases (no plugin.json, empty skills dir, etc.)

Tests use the existing test infrastructure with real file system
operations and verify actual sync output.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Explains the automatic naming resolution when multiple plugins
define skills with the same folder name.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Plan completed and behavior documented in docs/guides/plugins.mdx

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@christso christso force-pushed the feat/duplicate-skill-naming branch from 472b42b to 3dbef10 Compare January 28, 2026 01:30
Reduce test count from 110 to ~55:
- source-parser: 38 → 6 tests (consolidated assertions)
- integration: 25 → 7 tests (removed redundant scenarios)
- Removed separate GitHub integration test file

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@christso christso merged commit 4fb57bc into main Jan 28, 2026
1 check passed
@christso christso deleted the feat/duplicate-skill-naming branch January 28, 2026 01:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant